/* Isosurface extraction benchmark
 * 
 * Florian Speelman & Jannis Teunissen
 */

#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkVolume16Reader.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"
#include "vtkOutlineFilter.h"
#include "vtkCamera.h"
#include "vtkProperty.h"
#include "vtkPolyDataNormals.h"
#include "vtkContourFilter.h"
#include "vtkStripper.h"
#include "vtkDecimatePro.h"
#include "vtkImageShrink3D.h"

int main ()
{
	// Create the renderer and render window
	vtkRenderer *aRenderer = vtkRenderer::New();
	vtkRenderWindow *renWin = vtkRenderWindow::New();

	// Read in the data in the ../headsq directory
	vtkVolume16Reader *v16 = vtkVolume16Reader::New();
	v16->SetDataDimensions (256,256);
	v16->SetImageRange (1,94);
	v16->SetDataByteOrderToLittleEndian();
	v16->SetFilePrefix ("../fullHead/headsq");
	v16->SetDataSpacing (0.8, 0.8, 1.5);
	unsigned short mask = (1 << 15) - 1;
	v16->SetDataMask(mask);

	// Create isosurface extractor
	vtkContourFilter *skinExtractor = vtkContourFilter::New();
	skinExtractor->SetInputConnection(v16->GetOutputPort());
	skinExtractor->SetValue(0, 400);

	vtkPolyDataMapper *skinMapper = vtkPolyDataMapper::New();
	skinMapper->SetInputConnection(skinExtractor->GetOutputPort());
	skinMapper->ScalarVisibilityOff();
	vtkActor *skin = vtkActor::New();
	skin->SetMapper(skinMapper);

	aRenderer->AddActor(skin);
	renWin->AddRenderer(aRenderer);
	renWin->SetSize(1024, 768);

	int n, nsteps = 100;
	double totalTime;

	// Decrease input resolution
	totalTime = 0;
	vtkImageShrink3D *shrink = vtkImageShrink3D::New();
	shrink->SetInputConnection(v16->GetOutputPort());
	shrink->SetShrinkFactors(2,2,2);
	skinExtractor->SetInputConnection(shrink->GetOutputPort());
	renWin->Render();

	for( n = 0; n < nsteps; n++) {
		renWin->Render();
		aRenderer->GetActiveCamera()->Azimuth(360./nsteps);
		totalTime += aRenderer->GetLastRenderTimeInSeconds();
	}
	cout << "Average fps (ImageShrink3D) = " << nsteps / totalTime << endl;

	// Decimation 
	totalTime = 0;
	cout << "Decimating...\n";
	vtkDecimatePro *dec = vtkDecimatePro::New();
	skinExtractor->SetInputConnection(v16->GetOutputPort());
	dec->SetInputConnection(skinExtractor->GetOutputPort());
	dec->SetTargetReduction(.5);
	dec->SetPreserveTopology(0);
	dec->SetSplitting(1);
	dec->SetMaximumError(100000.);
	dec->Update();
	skinMapper->SetInputConnection(dec->GetOutputPort());
	renWin->Render();

	for( n = 0; n < nsteps; n++) {
		renWin->Render();
		aRenderer->GetActiveCamera()->Azimuth(360./nsteps);
		totalTime += aRenderer->GetLastRenderTimeInSeconds();
	}
	cout << "Average fps (DecimatePro) = " << nsteps / totalTime << endl;

	// Using vtkStripper
	totalTime = 0;
	vtkStripper *skinStripper = vtkStripper::New();
	skinExtractor->SetInputConnection(v16->GetOutputPort());
	skinStripper->SetInputConnection(skinExtractor->GetOutputPort());
	skinMapper->SetInputConnection(skinStripper->GetOutputPort());
	renWin->Render();

	for( n = 0; n < nsteps; n++) {
		renWin->Render();
		aRenderer->GetActiveCamera()->Azimuth(360./nsteps);
		totalTime += aRenderer->GetLastRenderTimeInSeconds();
	}
	cout << "Average fps (vtkStripper) = " << nsteps / totalTime << endl;

	// No optimizations
	totalTime = 0;
	skinMapper->SetInputConnection(skinExtractor->GetOutputPort());
	for( n = 0; n < nsteps; n++) {
		renWin->Render();
		aRenderer->GetActiveCamera()->Azimuth(360./nsteps);
		totalTime += aRenderer->GetLastRenderTimeInSeconds();
	}
	cout << "Average fps (no optimizations) = " << nsteps / totalTime << endl;

	return 0;
}
